import Env from '../utils/env'
import Logger from '../utils/logger';

type HttpMethod = 'GET' | 'POST';
interface RequestOptions {
  path: string;
  method: HttpMethod;
  headers?: Record<string, string>;
  params?: Record<string, any>;
}

/**
 * 请求类 - 单例模式封装 H5 请求（支持 hilink 接口或 fetch 请求）
 */
class Request {
  private static instance: Request;

  private constructor() {}

  public static getInstance(): Request {
    if (!Request.instance) {
      Request.instance = new Request();
    }
    return Request.instance;
  }

  public send(options: RequestOptions): Promise<any> {
      if (!window.hilink || typeof window.hilink.doHttpsRequest !== 'function') {
        return this.requestByFetch(options);
      }
      return this.requestByHilink(options);
  }

  private requestByHilink(options: RequestOptions): Promise<any> {
    return new Promise((resolve, reject) => {
      const { path, method, headers = {}, params = {} } = options;
      const jsonBody: any = {
        domain: Env.apiUrl,
        path,
        method,
        header: headers,
        param: { ...params }
      };
      // POST 请求必须添加 contentType
      if (method === 'POST') {
        jsonBody.param.contentType = 'json';
      }
      // hilink.doHttpsRequest 接口的回调形式
      const callbackName = `__hilink_result_callback_${Date.now()}`;
      let callbackTimer: any = -1;
      (window as any)[callbackName] = (resultStr: string) => {
        clearTimeout(callbackTimer);
        try {
          Logger.log(`请求地址：${Env.getEnv} ${method} ${path}`);
          Logger.log(`请求头部`, headers);
          Logger.log(`请求参数`, params);
          const result = JSON.parse(resultStr);
          Logger.log(`响应结果`, result);
          resolve(result);
        } catch (e) {
          Logger.log(`响应结果`, resultStr);
          resolve(resultStr); // 如果不是 JSON，就直接返回字符串
        }
        // 清理全局函数
        delete (window as any)[callbackName];
      };
      try {
        window.hilink.doHttpsRequest(JSON.stringify(jsonBody), callbackName);
        callbackTimer = setTimeout(() => {
          reject("timeout");
          // 清理全局函数
          delete (window as any)[callbackName];
        }, 10 * 1000)
      } catch (err) {
        reject(err);
      }
    });

  }

  private requestByFetch(options: RequestOptions): Promise<any> {
    return new Promise((resolve, reject) => {
      const { path, method, headers = {}, params = {} } = options;
      const url = new URL(`${Env.apiUrl}${path}`);
      let fetchOptions: RequestInit = {
        method,
        headers: {
          'Content-Type': 'application/json',
          ...headers,
        },
      };

      if (method === 'GET') {
        Object.entries(params).forEach(([key, value]) => {
          url.searchParams.append(key, String(value));
        });
      } else {
        fetchOptions.body = JSON.stringify(params);
      }
      return fetch(url.toString(), fetchOptions).then(async res => {
        Logger.log(`请求地址：${Env.getEnv} ${method} ${path}`);
        Logger.log(`请求头部`, fetchOptions.headers);
        Logger.log(`请求参数`, params);
        if (!res.ok) {
          Logger.log(`响应错误`, res);
          reject(res);
          return;
        }
        const json = await res.json();
        Logger.log(`响应结果`, json);
        return resolve(json);
      });
    });

  }
}

export default Request.getInstance();
